// Promise class方式

class Promise {
    // 构造函数
    constructor(executor) {
        // 添加属性
        this.PromiseState = 'pending'
        this.PromiseResult = null
        // 声明保存回调函数的对象
        this.callBacks = []
        // 保存实例对象的this的值
        const self = this
        // 声明resolve()和reject()
        function resolve(data) {
            // 判断状态(状态是否被修改过)
            if (self.PromiseState !== 'pending') {
                return
            }
            // 1. 修改对象的状态(promiseState)
            // 如果直接这么调用this会指向window;this.PromiseState = 'fulfilled'
            self.PromiseState = 'fulfilled'
            // 2. 设置对象结果值(promiseResult)
            self.PromiseResult = data
            // 如果是一个异步任务,需要在调用resolve函数的最后进行then方法的回调
            // 使用setTimeout使其变成异步任务
            setTimeout(() => {
                self.callBacks.forEach(item => {
                    item.onResolved(data)
                })
            })
        }
        function reject(data) {
            // 判断状态(状态是否被修改过)
            if (self.PromiseState !== 'pending') {
                return
            }
            self.PromiseState = 'rejected'
            self.PromiseResult = data
            setTimeout(() => {
                self.callBacks.forEach(item => {
                    item.onRejected(data)
                })
            })
        }
        // 捕获异常
        try {
            // 同步调用[执行器函数]
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }
    // then方法
    then(onResolved, onRejected) {
        // 用于解决保存回调函数时this的指向问题
        const self = this
        // 添加回调函数参数判断,即处理如果不传递回调函数参数的情况
        // 这块代码实现了异常穿透和值传递
        if (typeof onRejected !== 'function') {
            onRejected = reason => {
                throw reason
            }
        }
        if (typeof onResolved !== 'function') {
            onResolved = value => value
        }
        // 让then方法回返Promise对象使其支持链式调用
        return new Promise((resolve, reject) => {
            // 将相同代码进行封装
            function callback(exe) {
                try {
                    let result = exe(self.PromiseResult)

                    // 这里又分为两种情况一种是onResolved函数返回的是一个Promise对象,和非Promise对象
                    if (result instanceof Promise) {
                        // 返回结果是一个Promise对象
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    } else {
                        // 返回结果是一个非Promise对象,(返回状态为成功的Promise对象)
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }

            // 这里的then方法的调用者是一个Promise实例对象,所以可以使用this直接访问属性
            if (this.PromiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved)
                })
            }
            if (this.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected)
                })
            }
            // 异步任务时执行如下代码
            // 当状态未发生变化时(pending),说明是一个异步任务
            if (this.PromiseState === 'pending') {
                // 在等待异步任务执行完成之后才能调用then方法,所以需要将回调函数保存到then的外部!
                // 这种方式只能保存一组回调函数,如果是多次调用then函数,后面的回调函数会将前面过的回调函数覆盖
                // this.callBack = {
                //     onRejected,
                //     onResolved
                // }
                this.callBacks.push({
                    // 注意这里只是将两个函数进行保存,并没有执行,真正执行的地方在resolve和reject函数中
                    onResolved: function () {
                        callback(onResolved)
                    },
                    onRejected: function () {
                        callback(onRejected)
                    }
                })
            }
        })
    }
    // catch方法
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    // resolve 方法
    static resolve(value) {
        return new Promise((resolve, reject) => {
            // 判断参数类型
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            } else {
                // 非Promise对象
                resolve(value)
            }
        })
    }
    // reject 方法
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }
    // all 方法(它不属于实例对象的方法,属于类的静态方法)
    static all(promises) {
        // 返回结果为promise对象
        return new Promise((resolve, reject) => {
            // 声明一个记录成功次数的变量count
            let count = 0
            // 声明一个存放成功结果的数组arr
            let arr = []
            // 遍历参数
            for (let i = 0, length = promises.length; i < length; i++) {
                // 执行promise对象的回调函数then
                promises[i].then(v => {
                    // 这里不能直接调用resolve方法,
                    // 累加count计数
                    count++
                    // 将成功的结果存入arr
                    arr[i] = v
                    // 如果count与参数长度相等,说明全部为成功的Promise
                    if (count === length) {
                        // 调用resolve方法
                        resolve(arr)
                    }
                }, r => {
                    reject(r)
                })
            }
        })
    }
    // race 方法
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0, length = promises.length; i < length; i++) {
                // 执行promise对象的回调函数then
                promises[i].then(v => {
                    // 直接调用resolve方法即可,哪个先执行完成哪个先执行这个resolve
                    resolve(arr)
                }, r => {
                    reject(r)
                })
            }
        })
    }


}